import axios, { AxiosInstance, AxiosResponse } from 'axios'
import { orthancConfig, type DicomInstancePath } from '@/config/orthanc.config'

/**
 * DICOM 实例元数据接口
 */
export interface DicomInstanceMetadata {
  studyInstanceUID: string
  seriesInstanceUID: string
  sopInstanceUID: string
  patientName?: string
  patientID?: string
  patientBirthDate?: string
  patientSex?: string
  patientAge?: string
  studyDate?: string
  studyTime?: string
  studyDescription?: string
  seriesDescription?: string
  modality?: string
  institutionName?: string
  manufacturerModelName?: string
  imageWidth?: number
  imageHeight?: number
  numberOfFrames?: number
  pixelSpacing?: string
  sliceThickness?: string
}

/**
 * Orthanc DICOM-Web 服务类
 */
export class OrthancService {
  private httpClient: AxiosInstance

  constructor() {
    const axiosConfig: any = {
      baseURL: orthancConfig.baseUrl,
      timeout: orthancConfig.timeout,
      headers: orthancConfig.headers
    }

    // 如果配置了认证信息,则添加到请求中
    if (orthancConfig.auth) {
      axiosConfig.auth = orthancConfig.auth
    }

    this.httpClient = axios.create(axiosConfig)

    // 请求拦截器
    this.httpClient.interceptors.request.use(
      (config) => {
        console.log(`[Orthanc] 发送请求: ${config.method?.toUpperCase()} ${config.url}`)
        return config
      },
      (error) => {
        console.error('[Orthanc] 请求错误:', error)
        return Promise.reject(error)
      }
    )

    // 响应拦截器
    this.httpClient.interceptors.response.use(
      (response) => {
        console.log(`[Orthanc] 响应成功: ${response.status} ${response.config.url}`)
        return response
      },
      (error) => {
        console.error('[Orthanc] 响应错误:', error.response?.status, error.message)
        return Promise.reject(error)
      }
    )
  }

  /**
   * 通过Orthanc实例ID获取图像（使用Orthanc REST API）
   */
  async getDicomImageByInstanceId(instanceId: string): Promise<Blob> {
    try {
      // 尝试不同的图像端点
      const imageEndpoints = [
        `/instances/${instanceId}/preview`,
        `/instances/${instanceId}/image-uint8`,
        `/instances/${instanceId}/image-uint16`
      ]
      
      for (const endpoint of imageEndpoints) {
        try {
          console.log(`[Orthanc] 尝试获取图像: ${endpoint}`)
          
          const response: AxiosResponse<Blob> = await this.httpClient.get(endpoint, {
            responseType: 'blob',
            headers: {
              'Accept': 'image/jpeg, image/png, */*'
            }
          })
          
          if (response.data.size > 0) {
            console.log(`[Orthanc] 图像获取成功: ${endpoint}, 大小: ${response.data.size} bytes`)
            return response.data
          }
        } catch (error) {
          console.warn(`[Orthanc] 端点失败 ${endpoint}:`, error)
          continue
        }
      }
      
      throw new Error('所有图像端点都失败了')
    } catch (error) {
      console.error('[Orthanc] 获取DICOM图像失败:', error)
      throw new Error(`获取DICOM图像失败: ${error}`)
    }
  }

  /**
   * 获取 DICOM 实例图像（兼容旧接口）
   */
  async getDicomImage(instancePath: DicomInstancePath): Promise<Blob> {
    try {
      // 首先尝试通过UID找到Orthanc实例ID
      const instanceId = await this.findInstanceIdByUID(instancePath.sopInstanceUID)
      if (instanceId) {
        return await this.getDicomImageByInstanceId(instanceId)
      }
      
      // 如果找不到,尝试DICOM-Web方式（可能不工作）
      const { studyInstanceUID, seriesInstanceUID, sopInstanceUID, frameNumber } = instancePath
      const relativePath = `${orthancConfig.dicomWebPath}/studies/${studyInstanceUID}/series/${seriesInstanceUID}/instances/${sopInstanceUID}/frames/${frameNumber || 1}`
      
      console.log(`[Orthanc] 尝试DICOM-Web方式: ${relativePath}`)
      
      const response: AxiosResponse<Blob> = await this.httpClient.get(relativePath, {
        responseType: 'blob',
        headers: {
          'Accept': 'image/jpeg, image/png, application/dicom, */*'
        }
      })

      return response.data
    } catch (error) {
      console.error('[Orthanc] 获取DICOM图像失败:', error)
      throw new Error(`获取DICOM图像失败: ${error}`)
    }
  }

  /**
   * 获取 DICOM 实例元数据
   */
  async getDicomMetadata(instancePath: DicomInstancePath): Promise<DicomInstanceMetadata> {
    try {
      const { studyInstanceUID, seriesInstanceUID, sopInstanceUID } = instancePath
      const relativePath = `${orthancConfig.dicomWebPath}/studies/${studyInstanceUID}/series/${seriesInstanceUID}/instances/${sopInstanceUID}/metadata`
      
      console.log(`[Orthanc] 获取DICOM元数据: ${relativePath}`)
      
      const response = await this.httpClient.get(relativePath)
      const metadata = response.data

      // 解析DICOM标签
      const patientName = this.extractPatientName(metadata)
      const patientID = this.extractDicomTag(metadata, '00100020')?.Value?.[0]
      const patientBirthDate = this.extractDicomTag(metadata, '00100030')?.Value?.[0]
      const patientSex = this.extractDicomTag(metadata, '00100040')?.Value?.[0]
      const patientAge = this.extractDicomTag(metadata, '00101010')?.Value?.[0]
      const studyDate = this.extractDicomTag(metadata, '00080020')?.Value?.[0]
      const studyTime = this.extractDicomTag(metadata, '00080030')?.Value?.[0]
      const studyDescription = this.extractDicomTag(metadata, '00081030')?.Value?.[0]
      const seriesDescription = this.extractDicomTag(metadata, '0008103E')?.Value?.[0]
      const modality = this.extractDicomTag(metadata, '00080060')?.Value?.[0]
      const institutionName = this.extractDicomTag(metadata, '00080080')?.Value?.[0]
      const manufacturerModelName = this.extractDicomTag(metadata, '00081090')?.Value?.[0]
      const imageWidth = this.extractDicomTag(metadata, '00280011')?.Value?.[0]
      const imageHeight = this.extractDicomTag(metadata, '00280010')?.Value?.[0]
      const numberOfFrames = this.extractDicomTag(metadata, '00280008')?.Value?.[0]
      const pixelSpacing = this.extractPixelSpacing(metadata)
      const sliceThickness = this.extractDicomTag(metadata, '00180050')?.Value?.[0]

      return {
        studyInstanceUID,
        seriesInstanceUID,
        sopInstanceUID,
        patientName,
        patientID,
        patientBirthDate,
        patientSex,
        patientAge,
        studyDate,
        studyTime,
        studyDescription,
        seriesDescription,
        modality,
        institutionName,
        manufacturerModelName,
        imageWidth,
        imageHeight,
        numberOfFrames: numberOfFrames ? parseInt(numberOfFrames) : 1,
        pixelSpacing,
        sliceThickness
      }
    } catch (error) {
      console.error('[Orthanc] 获取DICOM元数据失败:', error)
      throw new Error(`获取DICOM元数据失败: ${error}`)
    }
  }

  /**
   * 获取研究列表（使用Orthanc REST API）
   */
  async getStudies(): Promise<any[]> {
    try {
      console.log(`[Orthanc] 获取研究列表 (REST API)`)
      
      const response = await this.httpClient.get('/studies')
      const studyIds = response.data
      
      console.log(`[Orthanc] 找到 ${studyIds.length} 个研究`)
      
      // 获取每个研究的详细信息
      const studies = []
      for (const studyId of studyIds.slice(0, 10)) { // 限制前10个
        try {
          const studyResponse = await this.httpClient.get(`/studies/${studyId}`)
          studies.push({
            id: studyId,
            ...studyResponse.data
          })
        } catch (error) {
          console.warn(`[Orthanc] 获取研究详情失败: ${studyId}`)
        }
      }
      
      return studies
    } catch (error) {
      console.error('[Orthanc] 获取研究列表失败:', error)
      throw new Error(`获取研究列表失败: ${error}`)
    }
  }

  /**
   * 获取系列列表
   */
  async getSeries(studyInstanceUID: string): Promise<any[]> {
    try {
      const relativePath = `${orthancConfig.dicomWebPath}/studies/${studyInstanceUID}/series`
      console.log(`[Orthanc] 获取系列列表: ${relativePath}`)
      
      const response = await this.httpClient.get(relativePath)
      return response.data
    } catch (error) {
      console.error('[Orthanc] 获取系列列表失败:', error)
      throw new Error(`获取系列列表失败: ${error}`)
    }
  }

  /**
   * 获取实例列表
   */
  async getInstances(studyInstanceUID: string, seriesInstanceUID: string): Promise<any[]> {
    try {
      const relativePath = `${orthancConfig.dicomWebPath}/studies/${studyInstanceUID}/series/${seriesInstanceUID}/instances`
      console.log(`[Orthanc] 获取实例列表: ${relativePath}`)
      
      const response = await this.httpClient.get(relativePath)
      return response.data
    } catch (error) {
      console.error('[Orthanc] 获取实例列表失败:', error)
      throw new Error(`获取实例列表失败: ${error}`)
    }
  }

  /**
   * 通过SOP Instance UID查找Orthanc实例ID
   */
  async findInstanceIdByUID(sopInstanceUID: string): Promise<string | null> {
    try {
      console.log(`[Orthanc] 查找实例ID: ${sopInstanceUID}`)
      
      // 获取所有实例
      const response = await this.httpClient.get('/instances')
      const instanceIds = response.data
      
      // 遍历实例查找匹配的UID
      for (const instanceId of instanceIds) {
        try {
          const instanceResponse = await this.httpClient.get(`/instances/${instanceId}`)
          const instanceData = instanceResponse.data
          
          if (instanceData.MainDicomTags?.SOPInstanceUID === sopInstanceUID) {
            console.log(`[Orthanc] 找到实例ID: ${instanceId}`)
            return instanceId
          }
        } catch (error) {
          continue
        }
      }
      
      console.warn(`[Orthanc] 未找到UID对应的实例: ${sopInstanceUID}`)
      return null
    } catch (error) {
      console.error('[Orthanc] 查找实例ID失败:', error)
      return null
    }
  }

  /**
   * 验证DICOM实例是否存在
   */
  async verifyInstanceExists(instancePath: DicomInstancePath): Promise<boolean> {
    try {
      // 首先尝试通过UID查找
      const instanceId = await this.findInstanceIdByUID(instancePath.sopInstanceUID)
      if (instanceId) {
        console.log('[Orthanc] 实例验证成功 (通过REST API)')
        return true
      }
      
      // 如果找不到,尝试DICOM-Web方式
      const { studyInstanceUID, seriesInstanceUID, sopInstanceUID } = instancePath
      const relativePath = `${orthancConfig.dicomWebPath}/studies/${studyInstanceUID}/series/${seriesInstanceUID}/instances/${sopInstanceUID}`
      
      console.log(`[Orthanc] 验证实例是否存在 (DICOM-Web): ${relativePath}`)
      
      await this.httpClient.get(relativePath)
      console.log('[Orthanc] 实例验证成功 (通过DICOM-Web)')
      return true
    } catch (error: any) {
      console.error('[Orthanc] 实例不存在或验证失败:', error.response?.status, error.message)
      return false
    }
  }

  /**
   * 批量获取实例元数据（并发优化版）
   */
  async batchGetInstancesMetadata(instanceIds: string[], concurrency = 8): Promise<Map<string, any>> {
    const metadataMap = new Map<string, any>()
    const errors: string[] = []

    // 分批并发获取
    for (let i = 0; i < instanceIds.length; i += concurrency) {
      const batch = instanceIds.slice(i, i + concurrency)
      
      const batchResults = await Promise.allSettled(
        batch.map(async (instanceId) => {
          try {
            const response = await this.httpClient.get(`/instances/${instanceId}`)
            return { instanceId, data: response.data }
          } catch (error) {
            console.warn(`[Orthanc] 获取实例元数据失败: ${instanceId}`, error)
            throw error
          }
        })
      )

      // 处理结果
      batchResults.forEach((result, idx) => {
        if (result.status === 'fulfilled') {
          metadataMap.set(result.value.instanceId, result.value.data)
        } else {
          errors.push(batch[idx])
        }
      })

      console.log(`[Orthanc] 批量获取进度: ${Math.min(i + concurrency, instanceIds.length)}/${instanceIds.length}`)
    }

    if (errors.length > 0) {
      console.warn(`[Orthanc] ${errors.length} 个实例元数据获取失败`)
    }

    return metadataMap
  }

  /**
   * 批量获取实例图像（并发优化版，带缓存）
   */
  async batchGetInstancesImages(
    instanceIds: string[], 
    concurrency = 8,
    onProgress?: (loaded: number, total: number) => void
  ): Promise<Map<string, Blob>> {
    const imageMap = new Map<string, Blob>()
    const errors: string[] = []
    let loadedCount = 0

    // 分批并发获取
    for (let i = 0; i < instanceIds.length; i += concurrency) {
      const batch = instanceIds.slice(i, i + concurrency)
      
      const batchResults = await Promise.allSettled(
        batch.map(async (instanceId) => {
          try {
            const imageBlob = await this.getDicomImageByInstanceId(instanceId)
            return { instanceId, blob: imageBlob }
          } catch (error) {
            console.warn(`[Orthanc] 获取实例图像失败: ${instanceId}`, error)
            throw error
          }
        })
      )

      // 处理结果
      batchResults.forEach((result, idx) => {
        if (result.status === 'fulfilled') {
          imageMap.set(result.value.instanceId, result.value.blob)
          loadedCount++
          
          // 回调进度
          if (onProgress) {
            onProgress(loadedCount, instanceIds.length)
          }
        } else {
          errors.push(batch[idx])
        }
      })

      console.log(`[Orthanc] 批量图像加载进度: ${loadedCount}/${instanceIds.length}`)
    }

    if (errors.length > 0) {
      console.warn(`[Orthanc] ${errors.length} 个实例图像获取失败`)
    }

    return imageMap
  }

  /**
   * 使用压缩格式获取图像（如果Orthanc支持）
   */
  async getDicomImageCompressed(instanceId: string): Promise<Blob> {
    try {
      // 尝试使用压缩端点
      const compressedEndpoints = [
        `/instances/${instanceId}/preview?quality=90`, // 带质量参数的预览
        `/instances/${instanceId}/preview`,
        `/instances/${instanceId}/image-uint8`
      ]
      
      for (const endpoint of compressedEndpoints) {
        try {
          const response: AxiosResponse<Blob> = await this.httpClient.get(endpoint, {
            responseType: 'blob',
            headers: {
              'Accept': 'image/jpeg, image/png, */*'
            }
          })
          
          if (response.data.size > 0) {
            return response.data
          }
        } catch (error) {
          continue
        }
      }
      
      throw new Error('所有压缩端点都失败了')
    } catch (error) {
      console.error('[Orthanc] 获取压缩DICOM图像失败:', error)
      throw error
    }
  }

  /**
   * 测试 Orthanc 连接
   */
  async testConnection(): Promise<boolean> {
    try {
      const response = await this.httpClient.get('/system')
      console.log('[Orthanc] 连接测试成功:', response.data)
      return true
    } catch (error) {
      console.error('[Orthanc] 连接测试失败:', error)
      return false
    }
  }

  /**
   * 从DICOM元数据中提取标签值
   */
  private extractDicomTag(metadata: any, tag: string): any {
    if (Array.isArray(metadata)) {
      return metadata.find(item => item[tag])?.[tag]
    }
    return metadata[tag]
  }

  /**
   * 提取病人姓名（处理多种格式）
   */
  private extractPatientName(metadata: any): string | undefined {
    const patientNameTag = this.extractDicomTag(metadata, '00100010')
    
    if (!patientNameTag?.Value?.[0]) {
      return undefined
    }
    
    const nameValue = patientNameTag.Value[0]
    
    // 处理不同的姓名格式
    if (typeof nameValue === 'string') {
      return nameValue
    }
    
    // DICOM Person Name 格式
    if (nameValue.Alphabetic) {
      return nameValue.Alphabetic
    }
    
    if (nameValue.Ideographic) {
      return nameValue.Ideographic
    }
    
    if (nameValue.Phonetic) {
      return nameValue.Phonetic
    }
    
    // 如果是对象但没有标准字段,尝试转换为字符串
    if (typeof nameValue === 'object') {
      return JSON.stringify(nameValue)
    }
    
    return String(nameValue)
  }

  /**
   * 提取像素间距信息
   */
  private extractPixelSpacing(metadata: any): string | undefined {
    const pixelSpacingTag = this.extractDicomTag(metadata, '00280030')
    
    if (!pixelSpacingTag?.Value) {
      return undefined
    }
    
    const spacing = pixelSpacingTag.Value
    if (Array.isArray(spacing) && spacing.length >= 2) {
      return `${spacing[0]} × ${spacing[1]} mm`
    }
    
    return String(spacing)
  }
}

// 导出单例实例
export const orthancService = new OrthancService()

